home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / osrc.arc / SMTPCLI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-30  |  19.0 KB  |  881 lines

  1. /*
  2.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <time.h>
  16. #include <setjmp.h>
  17. #ifdef UNIX
  18. #include <sys/types.h>
  19. #endif
  20. #include "global.h"
  21. #include "mbuf.h"
  22. #include "cmdparse.h"
  23. #include "proc.h"
  24. #include "socket.h"
  25. #include "timer.h"
  26. #include "netuser.h"
  27. #include "smtp.h"
  28.  
  29. extern char Badhost[];
  30. extern char *Tcpstates[];
  31. FILE *tmpfile();
  32. time_t time();
  33. static void smtp_send();
  34.  
  35. static struct timer smtpcli_t;
  36. static int32 gateway;
  37.  
  38. #ifdef SMTPTRACE
  39. int    Smtptrace = 0;            /* used for trace level */
  40. static int dosmtptrace();
  41. #endif
  42.  
  43. static int smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  44. static int smtpsessions = 0;        /* number of client connections
  45.                     * currently open */
  46. int    Smtpmode = 0;
  47.  
  48. static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  49.  
  50. static char quitcmd[] = "QUIT\r\n";
  51. static char eom[] = "\r\n.\r\n";
  52.  
  53. static int dogateway(),dosmtpmaxcli(),dotimer(),next_job(), setsmtpmode();
  54. static int sendfile();
  55. int smtptick(), dosmtp(), mlock(), rmlock();
  56. static void sendquit(),abort_trans(),retmail(),sendcmd();
  57. static void del_session(),del_job(), execjobs(),logerr();
  58. static struct smtpcli *newcb(),*lookup();
  59. static struct smtp_job *setupjob();
  60.  
  61. struct cmds smtpcmds[] = {
  62.     "gateway",    dogateway,    0,    0,    NULLCHAR,
  63.     "mode",        setsmtpmode,    0,    0,    NULLCHAR,
  64.     "kick",        smtptick,    0,    0,    NULLCHAR,
  65.     "maxclients",    dosmtpmaxcli,    0,    0,    NULLCHAR,
  66.     "timer",    dotimer,    0,    0,    NULLCHAR,
  67. #ifdef SMTPTRACE
  68.     "trace",    dosmtptrace,    0,    0,    NULLCHAR,
  69. #endif
  70.     NULLCHAR,    NULLFP,        0,    0,    
  71.     "subcommands: gateway kick maxclients timer trace",
  72.         NULLCHAR,
  73. };
  74.  
  75. int
  76. dosmtp(argc,argv,envp)
  77. int argc;
  78. char *argv[];
  79. void *envp;
  80. {
  81.     return subcmd(smtpcmds,argc,argv,envp);
  82. }
  83.  
  84. static int
  85. dosmtpmaxcli(argc,argv)
  86. int argc;
  87. char *argv[];
  88. {
  89.     int x;
  90.     if (argc < 2)
  91.         printf("%d\n",smtpmaxcli);
  92.     else {
  93.         x = atoi(argv[1]);
  94.         if (x > MAXSESSIONS)
  95.             printf("max clients must be <= %d\n",MAXSESSIONS);
  96.         else
  97.             smtpmaxcli = x;
  98.     }
  99.     return 0;
  100. }
  101.  
  102. static int
  103. setsmtpmode(argc,argv)
  104. int argc;
  105. char *argv[];
  106. {
  107.     if (argc < 2) {
  108.         printf("smtp mode: %s\n",
  109.             (Smtpmode & QUEUE) ? "queue" : "route");
  110.     } else {
  111.         switch(*argv[1]) {
  112.         case 'q':
  113.             Smtpmode |= QUEUE;
  114.             break;
  115.         case 'r':
  116.             Smtpmode &= ~QUEUE;
  117.             break;
  118.         default:
  119.             printf("Usage: smtp mode [queue | route]\n");
  120.             break;
  121.         }
  122.     }
  123.     return 0;
  124. }
  125. static int
  126. dogateway(argc,argv)
  127. int argc;
  128. char *argv[];
  129. {
  130.     int32 n;
  131.  
  132.     if(argc < 2){
  133.         printf("%s\n",inet_ntoa(gateway));
  134.     } else if((n = resolve(argv[1])) == 0){
  135.         printf(Badhost,argv[1]);
  136.         return 1;
  137.     } else
  138.         gateway = n;
  139.     return 0;
  140. }
  141.  
  142. #ifdef SMTPTRACE
  143. static int
  144. dosmtptrace(argc,argv)
  145. int argc;
  146. char *argv[];
  147. {
  148.     if (argc < 2)
  149.         printf("%d\n",Smtptrace);
  150.     else 
  151.         Smtptrace = atoi(argv[1]);
  152.     return 0;
  153. }
  154. #endif
  155.  
  156. /* Set outbound spool scan interval */
  157. static int
  158. dotimer(argc,argv)
  159. int argc;
  160. char *argv[];
  161. {
  162.     if(argc < 2){
  163.         printf("%lu/%lu\n",
  164.         (smtpcli_t.start - smtpcli_t.count)/(1000/MSPTICK),
  165.         smtpcli_t.start/(1000/MSPTICK));
  166.         return 0;
  167.     }
  168.     smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
  169.     smtpcli_t.arg = NULLCHAR;        /* dummy value */
  170.     smtpcli_t.start = atol(argv[1])*(1000/MSPTICK);    /* set timer duration */
  171.     start_timer(&smtpcli_t);        /* and fire it up */
  172.     return 0;
  173. }
  174.  
  175. /* this is the routine that gets called every so often to do outgoing mail
  176.    processing */
  177. int
  178. smtptick()
  179. {
  180.     register struct smtpcli *cb;
  181.     struct smtp_job *jp;
  182.     struct list *ap;
  183.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  184.     char    from[LINELEN], to[LINELEN];
  185.     char *cp, *cp1;
  186.     int32 destaddr;
  187.     FILE *wfile;
  188.  
  189. #ifdef SMTPTRACE
  190.     if (Smtptrace > 5)
  191.         printf("smtp daemon entered\n");
  192. #endif
  193.     for(filedir(Mailqueue,0,wfilename);wfilename[0] != '\0';
  194.         filedir(Mailqueue,1,wfilename)){
  195.  
  196.         /* save the prefix of the file name which it job id */
  197.         cp = wfilename;
  198.         cp1 = prefix;
  199.         while (*cp && *cp != '.')
  200.             *cp1++ = *cp++;
  201.         *cp1 = '\0';
  202.  
  203.         /* lock this file from the smtp daemon */
  204.         if (mlock(Mailqdir,prefix))
  205.             continue;
  206.  
  207.         sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
  208.         if ((wfile = fopen(tmpstring,READ_TEXT)) == NULLFILE) {
  209.             /* probably too many open files */
  210.             (void) rmlock(Mailqdir,prefix);
  211.             /* continue to next message. The failure
  212.             * may be temporary */
  213.             continue;
  214.         }
  215.  
  216.         (void) fgets(tmpstring,LINELEN,wfile);    /* read target host */
  217.         rip(tmpstring);
  218.  
  219.         if ((destaddr = mailroute(tmpstring)) == 0) {
  220.             fclose(wfile);
  221.             printf("** smtp: Unknown address %s\n",tmpstring);
  222.             (void) rmlock(Mailqdir,prefix);
  223.             continue;
  224.         }
  225.  
  226.         if ((cb = lookup(destaddr)) == NULLSMTPCLI) {
  227.             /* there are enough processes running already */
  228.             if (smtpsessions >= smtpmaxcli) {
  229. #ifdef SMTPTRACE
  230.                 if (Smtptrace) {
  231.                     printf("smtp daemon: too many processes\n");
  232.                 }
  233. #endif
  234.                 fclose(wfile);
  235.                 (void) rmlock(Mailqdir,prefix);
  236.                 break;
  237.             }
  238.             if ((cb = newcb()) == NULLSMTPCLI) {
  239.                 fclose(wfile);
  240.                 (void) rmlock(Mailqdir,prefix);
  241.                 break;
  242.             } 
  243.             cb->ipdest = destaddr;
  244.         } else {
  245.             /* This system is already is sending mail lets not
  246.             * interfere with its send queue.
  247.             */
  248.             if (cb->state != CLI_INIT_STATE) {
  249.                 fclose(wfile);
  250.                 (void) rmlock(Mailqdir,prefix);
  251.                 continue;
  252.             }
  253.         }
  254.  
  255.         (void) fgets(from,LINELEN,wfile);    /* read from */
  256.         rip(from);
  257.         if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  258.             fclose(wfile);
  259.             (void) rmlock(Mailqdir,prefix);
  260.             del_session(cb);
  261.             break;
  262.         }
  263.         while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  264.             rip(to);
  265.             if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  266.                 fclose(wfile);
  267.                 del_session(cb);
  268.             }
  269.         }
  270.         fclose(wfile);
  271. #ifdef SMTPTRACE
  272.         if (Smtptrace > 1) {
  273.             printf("queue job %s From: %s To:",prefix,from);
  274.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  275.                 printf(" %s",ap->val);
  276.             printf("\n");
  277.         }
  278. #endif
  279.     }
  280.  
  281.     /* start sending that mail */
  282.     execjobs();
  283.  
  284.     /* Restart timer */
  285.     start_timer(&smtpcli_t);
  286.     return 0;
  287. }
  288.  
  289. /* this is the master state machine that handles a single SMTP transaction */
  290. /* it is called with a queue of jobs for a particular host. */
  291. static void
  292. smtp_send(unused,cb)
  293. int unused;
  294. register struct smtpcli *cb;
  295. {
  296.     register char reply;
  297.     register struct list *tp;
  298.     struct sockaddr_in fsocket;
  299.     struct mbuf *bp,*bpl;
  300.     char *cp;
  301.     char tbuf[LINELEN];
  302.     int rcode;
  303.  
  304.     fsocket.sin_family = AF_INET;
  305.     fsocket.sin_addr.s_addr = cb->ipdest;
  306.     fsocket.sin_port = IPPORT_SMTP;
  307.  
  308.     cb->s = socket(AF_INET,SOCK_STREAM,0);
  309.     cb->state = CLI_OPEN_STATE;    /* init state placeholder */
  310. #ifdef SMTPTRACE
  311.     if (Smtptrace) 
  312.         printf("SMTP client Trying...\n");
  313. #endif
  314.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == 0){
  315. #ifdef SMTPTRACE
  316.     if (Smtptrace) 
  317.         printf("Connected\n");
  318. #endif
  319.         ;
  320.     } else {
  321.         cp = sockerr(cb->s);
  322. #ifdef SMTPTRACE
  323.         if (Smtptrace) 
  324.             printf("Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  325. #endif
  326.         log(cb->s,"Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  327.     }
  328.  
  329.     while(1) {
  330.         
  331.         if (recvline(cb->s,cb->buf,LINELEN) == -1)
  332.             goto quit;
  333.         rip(cb->buf);
  334. #ifdef SMTPTRACE
  335.         if (Smtptrace)
  336.             printf("smtp rcvd: '%s'\n",cb->buf);
  337. #endif
  338.  
  339.         /* Another line follows, ignore this one */
  340.         if(cb->buf[0] == '0' || cb->buf[3] == '-')
  341.             continue;
  342.  
  343.         reply = cb->buf[0];
  344.         rcode = atoi(cb->buf);
  345.  
  346.         /* if service shuting down */
  347.         if (rcode == 421) {
  348.             sendquit(cb);
  349.             continue;
  350.         }
  351.  
  352.         switch(cb->state) {
  353.         case CLI_OPEN_STATE:
  354.             if (reply != '2')
  355.                 sendquit(cb);
  356.             else {
  357.                 cb->state = CLI_HELO_STATE;
  358.                 sendcmd(cb,"HELO %s\r\nMAIL FROM:<%s>\r\n",
  359.                 Hostname,cb->jobq->from);
  360.             }
  361.             break;
  362.         case CLI_HELO_STATE:
  363.             if (reply != '2')
  364.                 sendquit(cb);
  365.             else 
  366.                 cb->state = CLI_MAIL_STATE;
  367.             break;            
  368.         case CLI_MAIL_STATE:
  369.             if (reply != '2')
  370.                 sendquit(cb);
  371.             else {
  372.                 cb->state = CLI_RCPT_STATE;
  373.                 cb->rcpts = 0;
  374.                 bpl = NULLBUF;
  375.                 for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  376.                     sprintf(tbuf,"RCPT TO:<%s>\r\n",tp->val);
  377.                     bp = qdata(tbuf,(int16)strlen(tbuf));
  378.                     if (bp == NULLBUF) {
  379.                         free_p(bpl);
  380.                         sendquit(cb);
  381.                         goto quit;
  382.                     }
  383.                     append(&bpl,bp);
  384.                     cb->rcpts++;
  385. #ifdef SMTPTRACE
  386.                     if (Smtptrace) {
  387.                         printf("smtp sent: %s",tbuf);
  388.                     }
  389. #endif
  390.                 }
  391.                 send_mbuf(cb->s,bpl,0,NULLCHAR,0);
  392.             }
  393.             break;
  394.         case CLI_RCPT_STATE:
  395.             if (reply == '5') {
  396.                 logerr(cb);
  397.             } else if (reply == '2') {
  398.                 cb->goodrcpt = 1;
  399.             } else {
  400.                 /* some kind of temporary failure */
  401.                 abort_trans(cb);
  402.                 break;
  403.             }
  404.             /* if more rcpts stay in this state */
  405.             if (--cb->rcpts != 0)
  406.                 break;
  407.  
  408.             /* check for no good rcpt on the list */
  409.             if (cb->goodrcpt == 0) {
  410.                 if (cb->errlog != NULLLIST)
  411.                     retmail(cb);
  412.                 (void) unlink(cb->wname);    /* unlink workfile */
  413.                 (void) unlink(cb->tname);    /* unlink text */
  414.                 abort_trans(cb);
  415.                 break;
  416.             }
  417.             /* if this file open fails abort */
  418.             if ((cb->tfile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  419.                 abort_trans(cb);
  420.             else {
  421.                 sendcmd(cb,"DATA\r\n");
  422.                 cb->state = CLI_SEND_STATE;
  423.             }
  424.             break;
  425.         case CLI_SEND_STATE:
  426.             if (reply == '3') {
  427.                 cb->state = CLI_UNLK_STATE;
  428.                 sendfile(cb);
  429.             } else {
  430.                 sendquit(cb);
  431.             }
  432.             break;
  433.         case CLI_UNLK_STATE:
  434.             /* if a good transfer or permanent failure remove job */
  435.             if (reply == '2' || reply == '5') {
  436.                 if (reply == '5')
  437.                     logerr(cb);
  438.                 /* close and unlink the textfile */
  439.                 if(cb->tfile != NULLFILE) {
  440.                     fclose(cb->tfile);
  441.                     cb->tfile = NULLFILE;
  442.                 }
  443.                 if (cb->errlog != NULLLIST)
  444.                     retmail(cb);
  445.                 (void) unlink(cb->tname);
  446.                 (void) unlink(cb->wname);    /* unlink workfile */
  447.                 log(cb->s,"SMTP sent job %s To: %s From: %s",
  448.                 cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  449.             }
  450.             if (next_job(cb)) {
  451.                 cb->state = CLI_MAIL_STATE;
  452.                 sendcmd(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  453.             } else {
  454.                 sendquit(cb);
  455.                 cb->state = CLI_QUIT_STATE;
  456.             }
  457.             break;
  458.         case CLI_IDLE_STATE:    /* used after a RSET and more mail to send */
  459.             if (reply != '2')
  460.                 sendquit(cb);
  461.             else {
  462.                 cb->state = CLI_MAIL_STATE;
  463.                 sendcmd(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  464.             }
  465.             break;            
  466.         case CLI_QUIT_STATE:
  467.             goto quit;
  468.             break;
  469.         }
  470.     }
  471. quit:
  472.     (void) close_s(cb->s);
  473.     if(cb->tfile != NULLFILE)
  474.         fclose(cb->tfile);
  475.     del_session(cb);
  476. }
  477.  
  478. /* abort the currrent job.
  479.  * If more work exists set up the next job if
  480.  * not then shut down.
  481. */
  482. static void
  483. abort_trans(cb)
  484. register struct smtpcli *cb;
  485. {
  486. #ifdef SMTPSTRACE
  487.     if (Smtptrace)
  488.         printf("smtpcli: abort transaction\n");
  489. #endif
  490.     if(cb->tfile != NULLFILE) {
  491.         fclose(cb->tfile);
  492.         cb->tfile = NULLFILE;
  493.     }
  494.     if (next_job(cb)) {
  495.         sendcmd(cb,"RSET\r\n");
  496.         cb->state = CLI_IDLE_STATE;
  497.     } else 
  498.         sendquit(cb);
  499. }
  500.  
  501. void
  502. static sendquit(cb)
  503. struct smtpcli *cb;
  504. {
  505.     cb->state = CLI_QUIT_STATE;
  506.     sendcmd(cb,quitcmd);    /* issue a quit command */
  507. }
  508.  
  509. /* Send message back to server */
  510. /*VARARGS*/
  511. static void
  512. sendcmd(cb,fmt,arg1,arg2)
  513. struct smtpcli *cb;
  514. char *fmt,*arg1,*arg2;
  515. {
  516.     struct mbuf *bp;
  517.     char tmpstring[256];
  518.  
  519. #ifdef SMTPTRACE
  520.     if (Smtptrace) {
  521.         printf("smtp sent: ");
  522.         printf(fmt,arg1,arg2);
  523.     }
  524. #endif
  525.     sprintf(tmpstring,fmt,arg1,arg2);
  526.     bp = qdata(tmpstring,(int16)strlen(tmpstring));
  527.     send_mbuf(cb->s,bp,0,NULLCHAR,0);
  528. }
  529.  
  530. /* create mail lockfile */
  531. int
  532. mlock(dir,id)
  533. char *dir,*id;
  534. {
  535.     char lockname[LINELEN];
  536.     int fd;
  537.  
  538.     /* Try to create the lock file in an atomic operation */
  539.     sprintf(lockname,"%s/%s.lck",dir,id);
  540.     if((fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT,0600)) == -1)
  541.         return -1;
  542.     close(fd);
  543.     return 0;
  544. }
  545.  
  546. /* remove mail lockfile */
  547. int
  548. rmlock(dir,id)
  549. char *dir,*id;
  550. {
  551.     char lockname[LINELEN];
  552.     sprintf(lockname,"%s/%s.lck",dir,id);
  553.     return(unlink(lockname));
  554. }
  555.  
  556. /* free the message struct and data */
  557. static void
  558. del_session(cb)
  559. register struct smtpcli *cb;
  560. {
  561.     register struct smtp_job *jp,*tp;
  562.     register int i;
  563.  
  564.     if (cb == NULLSMTPCLI)
  565.         return;
  566.     for(i=0; i<MAXSESSIONS; i++) 
  567.         if(cli_session[i] == cb) {
  568.             cli_session[i] = NULLSMTPCLI;
  569.             break;
  570.         }
  571.  
  572.     free(cb->wname);
  573.     free(cb->tname);
  574.     for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  575.             tp = jp->next;
  576.             del_job(jp);
  577.     }
  578.     del_list(cb->errlog);
  579.     free((char *)cb);
  580.     smtpsessions--;    /* number of connections active */
  581. }
  582.  
  583. static void
  584. del_job(jp)
  585. register struct smtp_job *jp;
  586. {
  587.     if ( *jp->jobname != '\0')
  588.         (void) rmlock(Mailqdir,jp->jobname);
  589.     free(jp->from);
  590.     del_list(jp->to);
  591.     free((char *)jp);
  592. }
  593.  
  594. /* delete a list of list structs */
  595. void
  596. del_list(lp)
  597. struct list *lp;
  598. {
  599.     register struct list *tp, *tp1;
  600.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  601.             tp1 = tp->next;
  602.             free(tp->val);
  603.             free((char *)tp);
  604.     }
  605. }
  606.  
  607. /* return message to sender */
  608. static void
  609. retmail(cb)
  610. struct smtpcli *cb;
  611. {
  612.     register struct list *lp;
  613.     register FILE *tfile;
  614.     register int c;
  615.     FILE *infile;
  616.     char *to;
  617.     time_t t;
  618.     
  619. #ifdef SMTPTRACE
  620.     if (Smtptrace > 5) {
  621.         printf("smtp job %s returned to sender\n",cb->wname);
  622.     }
  623. #endif
  624.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  625.     to = cb->jobq->from;
  626.     if (*to == '\0')
  627.         return;
  628.     if ((infile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  629.         return;
  630.     if ((tfile = tmpfile()) == NULLFILE) {
  631.         fclose(infile);
  632.         return;
  633.     }
  634.     time(&t);
  635.     fprintf(tfile,"Date: %s",ptime(&t));
  636.     fprintf(tfile,"Message-Id: <%ld@%s>\n",get_msgid(),Hostname);
  637.     fprintf(tfile,"From: MAILER-DAEMON@%s\n",Hostname);
  638.     fprintf(tfile,"To: %s\n",to);
  639.     fprintf(tfile,"Subject: Failed mail\n\n");
  640.     fprintf(tfile,"  ===== transcript follows =====\n\n");
  641.  
  642.     for (lp = cb->errlog; lp != NULLLIST; lp = lp->next)
  643.         fprintf(tfile,"%s\n",lp->val);
  644.  
  645.     fprintf(tfile,"\n  ===== Unsent message follows ====\n");
  646.  
  647.     while((c = getc(infile)) != EOF)
  648.         if (putc(c,tfile) == EOF)
  649.             break;
  650.     fclose(infile);
  651.     fseek(tfile,0L,0);
  652.     (void) mailuser(tfile,"",to);
  653.     fclose(tfile);
  654. }
  655.  
  656. /* look to see if a smtp control block exists for this ipdest */
  657. static struct smtpcli *
  658. lookup(destaddr)
  659. int32 destaddr;
  660. {
  661.     register int i;
  662.  
  663.     for(i=0; i<MAXSESSIONS; i++) {
  664.         if (cli_session[i] == NULLSMTPCLI)
  665.             continue;
  666.         if(cli_session[i]->ipdest == destaddr)
  667.             return cli_session[i];
  668.     }
  669.     return NULLSMTPCLI;
  670. }
  671.  
  672. /* create a new  smtp control block */
  673. static struct smtpcli *
  674. newcb()
  675. {
  676.     register int i;
  677.     register struct smtpcli *cb;
  678.  
  679.     for(i=0; i<MAXSESSIONS; i++) {
  680.         if(cli_session[i] == NULLSMTPCLI) {
  681.             cb = (struct smtpcli *)calloc(1,sizeof(struct smtpcli));
  682.             if (cb == NULLSMTPCLI)
  683.                 return(NULLSMTPCLI);
  684.             cb->wname = malloc((unsigned)strlen(Mailqdir)+JOBNAME);
  685.             if (cb->wname == NULLCHAR) {
  686.                 free((char *)cb);
  687.                 return(NULLSMTPCLI);
  688.             }
  689.             cb->tname = malloc((unsigned)strlen(Mailqdir)+JOBNAME);
  690.             if (cb->tname == NULLCHAR) {
  691.                 free(cb->wname);
  692.                 free((char *)cb);
  693.                 return(NULLSMTPCLI);
  694.             }
  695.             cb->state = CLI_INIT_STATE;
  696.             cli_session[i] = cb;
  697.             smtpsessions++;    /* number of connections active */
  698.             return(cb);
  699.         }
  700.     }
  701.     return NULLSMTPCLI;
  702. }
  703.  
  704. static void
  705. execjobs()
  706. {
  707.     register struct smtpcli *cb;
  708.     register int i;
  709.  
  710.     for(i=0; i<MAXSESSIONS; i++) {
  711.         cb = cli_session[i];
  712.         if (cb == NULLSMTPCLI) 
  713.             continue;
  714.         if(cb->state != CLI_INIT_STATE)
  715.             continue;
  716.  
  717.         sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
  718.         sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
  719.  
  720.         newproc("smtp_send", 1024, smtp_send, 0, cb,NULL);
  721.  
  722. #ifdef SMTPTRACE
  723.         if (Smtptrace) 
  724.             printf("Trying Connection to %s\n",inet_ntoa(cb->ipdest));
  725. #endif
  726.  
  727.  
  728.     }
  729. }
  730.     
  731. /* add this job to control block queue */
  732. static struct smtp_job *
  733. setupjob(cb,id,from)
  734. struct smtpcli *cb;
  735. char *id,*from;
  736. {
  737.     register struct smtp_job *p1,*p2;
  738.  
  739.     p1 = (struct smtp_job *)calloc(1,sizeof(struct smtp_job));
  740.     if (p1 == NULLJOB)
  741.         return NULLJOB;
  742.     p1->from = malloc((unsigned)strlen(from) + 1);
  743.     if (p1->from == NULLCHAR) {
  744.         free((char *)p1);
  745.         return NULLJOB;
  746.     }
  747.     strcpy(p1->from,from);
  748.     strcpy(p1->jobname,id);
  749.     /* now add to end of jobq */
  750.     if ((p2 = cb->jobq) == NULLJOB)
  751.         cb->jobq = p1;
  752.     else {
  753.         while(p2->next != NULLJOB)
  754.             p2 = p2->next;
  755.         p2->next = p1;
  756.     }
  757.     return p1;
  758. }
  759.  
  760. /* called to advance to the next job */
  761. static int
  762. next_job(cb)
  763. register struct smtpcli *cb;
  764. {
  765.     register struct smtp_job *jp;
  766.  
  767.     jp = cb->jobq->next;
  768.     del_job(cb->jobq);
  769.     if (jp == NULLJOB) {
  770.         cb->jobq = NULLJOB;
  771.         return 0;
  772.     }
  773.     /* remove the error log of previous message */
  774.     del_list(cb->errlog);
  775.     cb->errlog = NULLLIST;
  776.     cb->goodrcpt = 0;
  777.     cb->jobq = jp;
  778.     sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
  779.     sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
  780. #ifdef SMTPTRACE
  781.     if (Smtptrace > 5) {
  782.         printf("sending job %s\n",jp->jobname);
  783.     }
  784. #endif
  785.         return 1;
  786.  
  787. }
  788.  
  789.  
  790. /* mail routing funtion. For now just used the hosts file */
  791. int32 mailroute(dest)
  792. char *dest;
  793. {
  794.     int32 destaddr;
  795.  
  796.     /* look up address or use the gateway */
  797.     if ((destaddr = resolve(dest)) == 0)
  798.         if (gateway != 0) 
  799.             destaddr = gateway; /* Use the gateway  */
  800.     return destaddr;
  801.     
  802. }
  803.  
  804. /* save error reply for in error list */
  805. static void
  806. logerr(cb)
  807. struct smtpcli *cb;
  808. {
  809.     register struct list *lp,*tp;
  810.     if ((tp = (struct list *)calloc(1,sizeof(struct list))) == NULLLIST)
  811.         return;
  812.     if ((tp->val = malloc((unsigned)strlen(cb->buf)+1)) == NULLCHAR) {
  813.         free((char *)tp);
  814.         return;
  815.     }
  816.     /* find end of list */
  817.     if ((lp = cb->errlog) == NULLLIST)
  818.         cb->errlog = tp;
  819.     else {
  820.         while(lp->next != NULLLIST)
  821.             lp = lp->next;
  822.         lp->next = tp;
  823.     }
  824.     strcpy(tp->val,cb->buf);
  825. }
  826.  
  827. static int
  828. sendfile(cb)
  829. register struct smtpcli *cb;
  830. {
  831.     register int c;
  832.     char *cp;
  833.     register struct mbuf *bp;
  834.     int sawnl = 1;
  835.     int error = 0;
  836.  
  837.     for(;;) {
  838.         /* Hard to know what to do here */
  839.         if ((bp = alloc_mbuf(BUFSIZ)) == NULLBUF)
  840.             return EOF;
  841.         cp = bp->data;
  842.         while((c = fgetc(cb->tfile)) != EOF && bp->cnt < BUFSIZ-2){
  843.             if (c == '\r')    /* strip cr from some pc hosts */
  844.                 continue;
  845.             if (c == '\n') { /* send line end as \r\n */
  846.                 *cp++ = '\r';
  847.                 bp->cnt++;
  848.                 sawnl = 1;
  849.             } else {
  850.         /* special case of a line with just a . sent as ..  one it */
  851.                 if (c == '.' && sawnl) {
  852.                     c = fgetc(cb->tfile);
  853.                     if ( c != EOF && c != '\n' && c != '\r')
  854.                         ungetc(c,cb->tfile);
  855.                     else {
  856.                         *cp++ = '.';
  857.                         bp->cnt++;
  858.                     }
  859.                     c = '.';
  860.                 }
  861.                 sawnl = 0;
  862.             }
  863.             *cp++ = c;
  864.             bp->cnt++;
  865.         }                
  866.         if(bp->cnt != 0) {
  867.             if(send_mbuf(cb->s,bp,0,NULLCHAR,0) == -1){
  868.                 error = 1;
  869.                 break;
  870.             }
  871.         } else {
  872.             free_p(bp);
  873.             break;
  874.         }
  875.     }
  876.     fclose(cb->tfile);
  877.     cb->tfile = NULLFILE;
  878.     sendcmd(cb,eom);
  879.     return error;
  880. }
  881.